/**
 * Created by hjqi on 2016/2/10.
 */

var user_collection_name = require('../config/config').config.mongodb.user_collection;
var mongodb = require('../../db/mongodb');
var __db = new mongodb(user_collection_name);
var _getToken = require('../oauth/oauth2').getToken;
var Promise = require('promise');
var gitAdpt = require('../git/git_adapter');
var jwt = require('jsonwebtoken');
var logger = require('../log4js/log4js').logger('common.js');

exports.getTokenAndUser = function(req,res,cb,onlyToken){
    var db = req.db;
    var param = req.query;

    var _queryParam = {"id":param.id,"type":param.type};
    //to fix userid
    if(onlyToken)
        _queryParam = {"id":param.user,"type":param.type};

    __db.getWithParam(db,_queryParam , function (err,retObj) {

        if ( retObj === null || retObj === undefined || retObj.length === 0) {
            _getToken(req, res);
        } else {
            var token = retObj[0].token;
            if(onlyToken)
                cb(token);
            else{
                var _promise = new Promise(function (_resolve, _reject) {
                    gitAdpt.getGitHandle(param.type).getUserInfo(token, function (data,result) {
                        if (data !== null)
                            _resolve(data);
                        else
                            _reject(result);
                    });
                });
                //save db
                _promise.then(function (userInfo) {
                    userInfo.id = param.id;
                    userInfo.type = param.type;
                    var _param = {
                        "id": param.id,
                        "type": param.type
                    };

                    __db.updateWithParam(db, _param, userInfo, function (ret) {
                        if (!ret)
                            cb(userInfo);
                        else{
                            //db error
                            if( ret instanceof  Error){
                                cb(null,ret);
                            }else{
                                cb({});
                            }
                        }
                    });
                });

                _promise.catch(function (res) {
                    cb(null,res);
                });
            }


        }

    });

}

exports.removeExpireToken = function (req,callback){
    var db = req.db;
    var param = req.query;

    var _param = {
        "id":param.id,
        "type":param.type
    };
    __db.delWithParam(db,_param,callback);

}

exports.deepCopy = function(source) {
    return _deepCopyObj(source);
}

exports.getLimitsFromService = function(svc){
    return _computelimit(svc);
}

exports.getLimitsFromServiceForRelease = function(svc){
    return _releaselimit(_computelimit(svc));
}
/**
 *
 * 计算需要资源的差值，然后跟用户拥有资源比较
 *  如下，假如新服务需要资源为0或者小于旧服务就会出现负值的情况
 *  oldSvc:{
 *      	 "cpu_shares" : "0.5",
             "mem_limit" : "512Mi",
            }
 *  newSvc{
 *          "cpu_shares" : "0",
			"mem_limit" : "0Mi"
		  }
 */
exports.getLimitsFromServiceUpt = function(oldSvc,newSvc){
    if( resourceCheck( oldSvc ) &&  resourceCheck( newSvc)  ){
        return {
            cores:(newSvc.node.cpu_shares * newSvc.rcnum) - (oldSvc.node.cpu_shares * oldSvc.rcnum),
            memory:(_getMemoryNumer(newSvc.node.mem_limit) * newSvc.rcnum) - (_getMemoryNumer(oldSvc.node.mem_limit) * oldSvc.rcnum)
        };
    }else{
        logger.warn("[#getLimitsFromServiceUpt] can't get svc.node.cpu_shares ") ;
        return {
            cores:0,
            memory:0
        };
    }
}
/**
 * 对象属性有效性检查，对于非必然存在的属性需要做判断（正确编程的习惯之一，据说垃圾程序员基本不做判断）
 */
function resourceCheck(svc) {
    if( svc && svc.node){
        svc.node.cpu_shares = svc.node.cpu_shares|| 0;
        svc.node.mem_limit=  svc.node.mem_limit || 0 ;
        svc.rcnum = svc.rcnum|| 0 ;
        return true ;
    }
    return false ;
}

exports.getLimitsFromServiceScale = function(svc,scale_num){
    var _rc = scale_num - svc.rcnum;
    return {
        cores:(svc.node.cpu_shares * _rc),
        memory:(_getMemoryNumer(svc.node.mem_limit) * _rc)
    };
}

exports.getLimitsFromCompose = function(svcs){
    return _computelimits(svcs);
}

exports.getLimitsFromComposeForRelease = function(svcs){
    return _releaselimit(_computelimits(svcs));
}

exports.getLimitsFromComposeUpt = function(add_svcs,release_svcs){
    var _add =  _computelimits(add_svcs);
    var _del = _computelimits(release_svcs);
    return {
        cores:_add.cores - _del.cores,
        memory:_add.memory - _del.memory
    }
}

exports.generateUUID = function(len, radix){
    //for k8s service name
    var firstchars = 'abcdefghijklmnopqrstuvwxyz'.split('');
    var chars = '0123456789abcdefghijklmnopqrstuvwxyz'.split('');
    var uuid = [], i;
    radix = radix || chars.length;

    if (len) {
        uuid[0] = firstchars[0 | Math.random()*radix];
        // Compact form
        for (i = 1; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
    } else {
        // rfc4122, version 4 form
        var r;

        // rfc4122 requires these characters
        uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
        uuid[14] = '4';

        // Fill in random data.  At i==19 set the high bits of clock sequence as
        // per rfc4122, sec. 4.1.5
        for (i = 0; i < 36; i++) {
            if (!uuid[i]) {
                r = 0 | Math.random()*16;
                uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
            }
        }
    }

    return uuid.join('');
}

exports.encodeTokenData =function(data){
    return jwt.sign(data,"naturecloud");
}

exports.decodeTokenData = function(token){
    return jwt.decode(token);
}
/**
 *  check if it is natureIO.cloud cluster or free-host cluster
 */
exports.checkIfFreeHost = function(cluster_id ) {
    if( cluster_id === 'default' ){
        return false ;
    }
    return true ;
}

/**
 * check the object is any properties beside prototype
 * @param obj
 * @returns {boolean}
 */
exports.isOwnEmpty = function (obj) {
    if( typeof obj ==  "string"){
        return true ;
    }
    for(var name  in obj)
    {
        if(obj.hasOwnProperty(name))  {
            return false;
        }
    }
    return true;
};

exports.startWith=function(str,substr){
    if( str && substr){
        if ( str.substring(0,substr.length)== substr ){
            return true ;
        }
    }
    return false ;
}

exports.myReturn=function(ret,error,data){
    return {
        ret:ret,
        error:(error||""),
        data:(data||{})
    };
}

exports.PVPolicy = {
    REUSE:1,
    CLEANFILES:2
}

exports.emptyPromise = function(data) {
    data = data || {};
    return new Promise(function (resolve,reject) {
        resolve(data) ;
    }) ;
}

exports.encodePathToVolname = function(path) {
    return path.replace(/\//g,'-');
}

exports.isEmptyObject = function(value){
    return (Object.prototype.isPrototypeOf(value) && Object.keys(value).length === 0);
}

function _computelimit(svc){
    return {
        cores:(svc.node.cpu_shares===undefined?0:svc.node.cpu_shares * svc.rcnum),
        memory:(svc.node.mem_limit===undefined?0:_getMemoryNumer(svc.node.mem_limit) * svc.rcnum)
    };
}

function _computelimits(svcs){
    var _ret = {
        cores:0,
        memory:0
    }
    svcs.forEach(function(svc){
        var _limit = _computelimit(svc);
        _ret.cores += _limit.cores;
        _ret.memory += _limit.memory;
    });
    return _ret;
}

function _releaselimit(resource){
    return {
        cores: -resource.cores,
        memory:-resource.memory
    }
}

function _getMemoryNumer(memory){
    var _ret = 0;
    if(memory.indexOf('Mi') !== -1){
        _ret = parseInt(memory.replace('Mi',''));
    }else if(memory.indexOf('Gi') !== -1){
        _ret = parseInt(memory.replace('Gi',''))*1024;
    }
    return _ret;
}

function _deepCopyObj(source){
    var result={};
    for (var key in source) {
        if(Object.prototype.toString.call(source[key])==='[object Object]')
            result[key] = _deepCopyObj(source[key]);
        else if(Object.prototype.toString.call(source[key])==='[object Array]')
            result[key] = source[key].slice();
        else
            result[key]  = source[key];
    }
    return result;
}



Buffer.prototype.toByteArray = function () {
    return Array.prototype.slice.call(this, 0)
}
